<?php
namespace App\Storage;

use EasySwoole\Component\Singleton;
use EasySwoole\EasySwoole\Config;

/**
 * 存储最新的10000条消息
 * 使用了文件所避免多个协程之间读取冲突
 * 暂时使用文件的形式存储
 * 后面修改成redis存储，定时更新到mysql
 * Class ChatMessage
 * @package App\Storage
 */
class ChatMessageFile {

    use Singleton;

    protected $storage;
    protected $capacity;
    protected $initialization = false;

    /**
     * ChatMessage constructor.
     * @param int $capacity
     */
    function __construct(int $capacity = 10000)
    {
        $this->capacity = $capacity;
        $this->storage = $this->createStorage();
        if (is_writable($this->storage)) {
            $this->initialization = true;
        }
    }

    /**
     * 存储一条消息
     * 格式: "{"fromUserFd":1,"action":WebSocketEvent::,"username":"username","avatar":"avatar","shopId":"shopId"}"
     * @param $message
     * @return bool
     */
    public function saveMessage($message) {
        if ($handle = fopen($this->storage,'r+')) {
            clearstatcache() && flock($handle, LOCK_EX); //清空文件缓存，并给句柄加写入锁
            $content = fread($handle,filesize($this->storage));
            $cache = unserialize($content) ?? [];
            array_unshift($cache,$message);
            $cacheContent = serialize(array_slice($cache, 0, $this->capacity)); //只存capacity条记录
            return ftruncate($handle, 0) && rewind($handle) && fwrite($handle, $cacheContent) && fclose($handle);
        }

        return false;
    }

    /**
     * 获取全部消息。按capacity
     * @return array|mixed
     */
    public function readMessage() {
        if ($handle = fopen($this->storage,'r')) {
            clearstatcache() && flock($handle, LOCK_SH);
            $content = fread($handle, filesize($this->storage));
            $cache = unserialize($content) ?? [];
            return $cache;
        }

        return [];
    }

    /**
     * 创建一个文件来存储消息
     * @return bool|string
     */
    function createStorage() {
        $location = is_writeable('/dev/shm') ? '/dev/shm' : sys_get_temp_dir();
//        $location = Config::getInstance()->getConf('TEMP_DIR');
        $cache = $location . DIRECTORY_SEPARATOR . date('Ymd') . '.cached';
        if (file_exists($cache)) { // 文件持久化保存在本地
            return $cache;
        }
        if (file_put_contents($cache,'a:0:{}',LOCK_EX)) { //写入锁
            return $cache;
        }
        return false;
    }

}